#pragma once

#include <utility>
#include <tuple>

namespace impl
{
	template <typename Ty, typename Head, typename... Tails>
	struct _exist_condition_helper
	{
		constexpr static bool value = sizeof...(Tails) == 0 ?
			false : _exist_condition_helper<Ty, Tails...>::value;
	};

	template <typename Ty, typename... Tails>
	struct _exist_condition_helper<Ty, Ty, Tails...>
	{
		constexpr static bool value = true;
	};
}

template <typename Ty, typename... Args>
struct exist_condition
{
	constexpr static bool value = impl::_exist_condition_helper<Ty, Args...>::value;
};

template <typename Host, typename... Prereqs>
class bounded
{
	std::reference_wrapper<Host> _host;
	std::tuple<std::reference_wrapper<Prereqs>...> _src;
public:
	bounded(Host &host_, Prereqs&... src_)
		:_host(host_), _src(std::make_tuple(std::reference_wrapper<Prereqs>(src_)...))
	{

	}

	Host& host()
	{
		_host.get();
	}

	template <typename Ty>
	auto& condition()
	{
		return std::get<std::reference_wrapper<Ty>>().get();
	}

	template <typename Ty>
	bounded<Host, Prereqs..., Ty> satisfy(Ty &cond_)
	{
		return bounded(_host.get(), _src.get()...);
	}
};